home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CU Amiga Super CD-ROM 17
/
CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso
/
CUCD
/
Programming
/
DiceSource
/
src
/
dc1
/
rules.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-09-09
|
26KB
|
1,040 lines
/*
* (c)Copyright 1992-1997 Obvious Implementations Corp. Redistribution and
* use is allowed under the terms of the DICE-LICENSE FILE,
* DICE-LICENSE.TXT.
*/
/*
* RULES.C
*
* Note that certain operations are available for store-down optimization.
* That is, char a, b; a = ~b; ... we can do the invert operation on a byte.
* These operators are: and,or,xor,invert,add,sub
*
* Note: void detection rules should only apply for TID_INT types since
* external arrays[] will have size 0
*
* only code gen routines associated with data movement need
* understand bit field storage types and only GenCast() &
* assignment exp tree routines.
*/
#include "defs.h"
Prototype void BinaryRules(Exp *);
Prototype void BinaryArithRules(Exp *);
Prototype void BinaryLogicRules(Exp *);
Prototype void UnaryLogicRules(Exp *);
Prototype void UnaryRules(Exp *);
Prototype void UnaryArithRules(Exp *);
Prototype void ShiftRules(Exp *);
Prototype void AddRules(Exp *);
Prototype void SubRules(Exp *);
Prototype void FloatingRules(Exp *);
Prototype void AssignRules(Exp *);
Prototype void InitRules(Exp **, Type *);
Prototype void CompareRules(Exp *, int);
Prototype void MatchRules(Exp *);
Prototype void OptBinaryArithRules(Exp *);
Prototype void OptBinaryRules(Exp *);
Prototype int CheckConversion(Exp *, Type *, Type *);
Prototype int CreateBinaryResultStorage(Exp *, short);
Prototype int CreateUnaryResultStorage(Exp *, short);
Local int CastIfConstantFit(Exp **, Type *);
Prototype short AutoResultStorage(Exp *);
/*
* Standard Binary Rules
*/
void
BinaryRules(exp)
Exp *exp;
{
Type *t1;
Type *t2;
short doUnsigned;
if (exp->ex_Flags & EF_ASSEQ)
return(AssignRules(exp));
t1 = exp->ex_ExpL->ex_Type;
t2 = exp->ex_ExpR->ex_Type;
doUnsigned = 0;
Assert(t1);
Assert(t2);
if (t1->Id != TID_INT || t2->Id != TID_INT) {
yerror(exp->ex_LexIdx, EERROR_EXPECTED_INT_TYPE);
exp->ex_Type = &LongType;
return;
}
if ((t1->Size==0 && t1->Id==TID_INT) || (t2->Size==0 && t2->Id==TID_INT)) {
yerror(exp->ex_LexIdx, EERROR_UNEXPECTED_VOID_TYPE);
exp->ex_Type = &LongType;
return;
}
if (t1->Id == TID_INT && (t1->Flags & TF_UNSIGNED))
doUnsigned = 1;
if (t2->Id == TID_INT && (t2->Flags & TF_UNSIGNED))
doUnsigned = 1;
if (t1->Id == TID_INT && (t1->Size < INT_SIZE || (doUnsigned && (t1->Flags & TF_UNSIGNED) == 0))) {
if (doUnsigned)
InsertCast(&exp->ex_ExpL, &ULongType);
else
InsertCast(&exp->ex_ExpL, &LongType);
}
if (t2->Id == TID_INT && (t2->Size < INT_SIZE || (doUnsigned && (t2->Flags & TF_UNSIGNED) == 0))) {
if (doUnsigned)
InsertCast(&exp->ex_ExpR, &ULongType);
else
InsertCast(&exp->ex_ExpR, &LongType);
}
if (doUnsigned)
exp->ex_Type = &ULongType;
else
exp->ex_Type = &LongType;
}
void
BinaryArithRules(exp)
Exp *exp;
{
if (exp->ex_ExpL->ex_Type->Id == TID_FLT || exp->ex_ExpR->ex_Type->Id == TID_FLT) {
FloatingRules(exp);
return;
}
BinaryRules(exp);
}
/*
* Optimized Binary Arithmatic Rules. This allows the two source
* operands to be of smaller types than the destination. For
* example, in genarith.c/GenStar() (multiply), so the MULS/MULU
* instruction may be optimized in.
*
* Note that in this case the result type is allowed to be either
* a short or a long, but not a char. This compromise makes code
* generation easier.
*/
void
OptBinaryRules(exp)
Exp *exp;
{
Type *t1;
Type *t2;
Type *t;
short doUnsigned;
short size;
if (exp->ex_Flags & EF_ASSEQ)
return(AssignRules(exp));
t1 = exp->ex_ExpL->ex_Type;
t2 = exp->ex_ExpR->ex_Type;
doUnsigned = 0;
Assert(t1);
Assert(t2);
if (t1->Id != TID_INT || t2->Id != TID_INT) {
yerror(exp->ex_LexIdx, EERROR_EXPECTED_INT_TYPE);
exp->ex_Type = &LongType;
return;
}
if (t1->Size == 0 || t2->Size == 0) {
yerror(exp->ex_LexIdx, EERROR_UNEXPECTED_VOID_TYPE);
exp->ex_Type = &LongType;
return;
}
if (t1->Flags & TF_UNSIGNED)
doUnsigned = 1;
if (t2->Flags & TF_UNSIGNED)
doUnsigned = 1;
size = 2;
if (t1->Size > size)
size = t1->Size;
if (t2->Size > size)
size = t2->Size;
if (doUnsigned) {
if (size == 2)
t = &UShortType;
else
t = &ULongType;
} else {
if (size == 2)
t = &ShortType;
else
t = &LongType;
}
if (t1 != t)
InsertCast(&exp->ex_ExpL, t);
if (t2 != t)
InsertCast(&exp->ex_ExpR, t);
if (exp->ex_Type && exp->ex_Type->Id == TID_INT) {
if (exp->ex_Type->Size == 1)
exp->ex_Type = (doUnsigned) ? &UShortType : &ShortType;
} else {
exp->ex_Type = (doUnsigned) ? &ULongType : &LongType;
}
}
void
OptBinaryArithRules(exp)
Exp *exp;
{
if (exp->ex_ExpL->ex_Type->Id == TID_FLT || exp->ex_ExpR->ex_Type->Id == TID_FLT) {
FloatingRules(exp);
return;
}
OptBinaryRules(exp);
}
/*
* For logic operations. If the result type is known we
* optimize to the largest type of the three (two args and
* result type).
*/
void
BinaryLogicRules(exp)
Exp *exp;
{
Exp *e1;
Exp *e2;
Type *type;
if ((type = exp->ex_Type) == NULL || type->Id != TID_INT) {
BinaryRules(exp);
return;
}
/*
* Extend or truncate to the return type since all other bits will be
* ignored (and for logic operations we can cut it off like this no prob)
*/
e1 = exp->ex_ExpL;
e2 = exp->ex_ExpR;
if (e1->ex_Type->Id == TID_FLT || e2->ex_Type->Id == TID_FLT) {
yerror(exp->ex_LexIdx, EERROR_EXPECTED_INT_TYPE);
}
if (e1->ex_Type != type)
InsertCast(&exp->ex_ExpL, type);
if (e2->ex_Type != type)
InsertCast(&exp->ex_ExpR, type);
}
/*
* The result is the type of the argument or the type the parent expects,
* whichever is larger. Example (byte). If parent expects byte we do not
* need to cast to <partype>, but if it does not we MUST cast to the parent's
* type.
*
* [00]80 ^ -1 (byte) -> [FF]7F
*/
void
UnaryLogicRules(exp)
Exp *exp;
{
Exp *e1;
Type *type = exp->ex_Type;
Type *t1;
if (type == NULL || type->Id != TID_INT) {
UnaryRules(exp);
return;
}
e1 = exp->ex_ExpL;
t1 = e1->ex_Type;
if (type->Size == 0) {
yerror(e1->ex_LexIdx, EERROR_UNEXPECTED_VOID_TYPE);
type = &LongType;
}
if (t1->Id == TID_FLT) {
yerror(e1->ex_LexIdx, EERROR_EXPECTED_INT_TYPE);
type = &LongType;
}
if (type != t1)
InsertCast(&exp->ex_ExpL, type);
}
void
UnaryRules(exp)
Exp *exp;
{
Type *t;
short doUnsigned;
t = exp->ex_ExpL->ex_Type;
doUnsigned = 0;
Assert(t);
if (t->Id == TID_INT && (t->Flags & TF_UNSIGNED))
doUnsigned = 1;
if (t->Id == TID_INT && t->Size < INT_SIZE) {
if (t->Size == 0)
yerror(exp->ex_LexIdx, EERROR_UNEXPECTED_VOID_TYPE);
if (doUnsigned)
InsertCast(&exp->ex_ExpL, &ULongType);
else
InsertCast(&exp->ex_ExpL, &LongType);
}
if (doUnsigned)
exp->ex_Type = &ULongType;
else
exp->ex_Type = &LongType;
}
void
UnaryArithRules(exp)
Exp *exp;
{
Exp *e1 = exp->ex_ExpL;
if (e1->ex_Type->Id == TID_FLT) {
exp->ex_Type = e1->ex_Type;
return;
}
UnaryRules(exp);
}
void
ShiftRules(exp)
Exp *exp;
{
Exp *e1 = exp->ex_ExpL;
Exp *e2 = exp->ex_ExpR;
Type *t1 = e1->ex_Type;
Type *t2 = e2->ex_Type;
Assert(t1);
Assert(t2);
if (exp->ex_Flags & EF_ASSEQ) {
exp->ex_Type = t1;
return;
}
if (t1->Size != 4) {
if (t1->Size == 0)
yerror(e1->ex_LexIdx, EERROR_UNEXPECTED_VOID_TYPE);
if (t1->Flags & TF_UNSIGNED)
InsertCast(&exp->ex_ExpL, &ULongType);
else
InsertCast(&exp->ex_ExpL, &LongType);
}
exp->ex_Type = exp->ex_ExpL->ex_Type;
}
/*
* AddRules(exp)
*
* Basically handle the special case of (ary/ptr + int) and (int + ary/ptr)
* Note that in this case the size of the 'int' is not cast.
*/
void
AddRules(exp)
Exp *exp;
{
Type *t1 = exp->ex_ExpL->ex_Type;
Type *t2 = exp->ex_ExpR->ex_Type;
Assert(t1);
Assert(t2);
exp->ex_Token = 0;
if ((t1->Id == TID_PTR || t1->Id == TID_ARY) && t2->Id == TID_INT) {
if (t1->SubType->Size == 0 && t1->SubType->Id == TID_INT)
yerror(exp->ex_LexIdx, EERROR_UNEXPECTED_VOID_TYPE);
if (t2->Size == 0)
yerror(exp->ex_LexIdx, EERROR_UNEXPECTED_VOID_TYPE);
exp->ex_Token = 1;
exp->ex_Type = t1;
/* xxx if autoassign insert type */
} else if (t1->Id == TID_INT && (t2->Id == TID_PTR || t2->Id == TID_ARY)) {
Exp *etmp = exp->ex_ExpL;
if (t1->Size == 0)
yerror(exp->ex_LexIdx, EERROR_UNEXPECTED_VOID_TYPE);
if (t2->SubType->Size == 0 && t2->SubType->Id == TID_INT)
yerror(exp->ex_LexIdx, EERROR_UNEXPECTED_VOID_TYPE);
exp->ex_ExpL = exp->ex_ExpR;
exp->ex_ExpR = etmp;
exp->ex_Type = t2;
exp->ex_Token = 1;
if (exp->ex_Flags & EF_ASSEQ)
yerror(exp->ex_LexIdx, EERROR_ILLEGAL_PTR_ARITH);
/* xxx if autoassign insert type */
} else {
if (t1->Size == 0)
yerror(exp->ex_LexIdx, EERROR_UNEXPECTED_VOID_TYPE);
if (t2->Size == 0)
yerror(exp->ex_LexIdx, EERROR_UNEXPECTED_VOID_TYPE);
if (exp->ex_Type && exp->ex_Type->Id == TID_INT && t1->Id == TID_INT && t2->Id == TID_INT) {
if (exp->ex_Type != t1)
InsertCast(&exp->ex_ExpL, exp->ex_Type);
if (exp->ex_Type != t2)
InsertCast(&exp->ex_ExpR, exp->ex_Type);
} else {
BinaryArithRules(exp);
}
}
}
/*
* SubRules() Basically handle ptr - ptr and let other routines
* worry about other combinations.
*/
void
SubRules(exp)
Exp *exp;
{
Type *t1 = exp->ex_ExpL->ex_Type;
Type *t2 = exp->ex_ExpR->ex_Type;
if (t1->Id == TID_ARY) {
InsertCast(&exp->ex_ExpL, TypeToPtrType(t1->SubType));
t1 = exp->ex_ExpL->ex_Type;
}
if (t2->Id == TID_ARY) {
InsertCast(&exp->ex_ExpR, TypeToPtrType(t2->SubType));
t2 = exp->ex_ExpR->ex_Type;
}
if (t1->Id == TID_PTR && t2->Id == TID_PTR) {
exp->ex_Token = 2;
exp->ex_Type = &LongType;
} else {
if (t2->Id == TID_PTR)
yerror(exp->ex_ExpR->ex_LexIdx, EERROR_ILLEGAL_PTR_ARITH);
AddRules(exp);
}
}
/*
* floating rules (binary). One or both sides are FP, cast to the largest
* of the two, except if EF_ASSEQ cast to lhs.
*/
void
FloatingRules(exp)
Exp *exp;
{
Type *t1 = exp->ex_ExpL->ex_Type;
Type *t2 = exp->ex_ExpR->ex_Type;
#ifdef REGISTERED
if (exp->ex_Flags & EF_ASSEQ) {
if (t1 != t2)
InsertCast(&exp->ex_ExpR, t1);
exp->ex_Type = t1;
return;
}
if (t1->Id == TID_FLT && t2->Id == TID_FLT) {
if (t1->Size > t2->Size)
InsertCast(&exp->ex_ExpR, t1);
else if (t2->Size > t1->Size) {
InsertCast(&exp->ex_ExpL, t2);
t1 = t2;
}
} else if (t1->Id == TID_FLT) {
InsertCast(&exp->ex_ExpR, t1);
} else {
InsertCast(&exp->ex_ExpL, t2);
t1 = t2;
}
exp->ex_Type = t1;
#else
yerror(exp->ex_LexIdx, EUNREG_FLOATINGPT);
#endif
}
/*
* cast the right side to the left side's type
*
* exception: if left side is a bitfield right side is cast to a long
* if right side is a bitfield it is cast to a long
*
* assign takes this into account
*/
void
AssignRules(exp)
Exp *exp;
{
Assert(exp->ex_ExpL);
Assert(exp->ex_ExpR);
InitRules(&exp->ex_ExpR, exp->ex_ExpL->ex_Type);
/*
* Old code: returned the right hand type.
*
* New code: returns the left hand type if a bitfield, else the righthand
* type.
*
* Properly, this code should always return the LEFT hand type. It
* turns out that the right hand and left hand types are the same in all
* cases except for bitfields. at least, they are supposed to be... I'm
* not 100% sure, so for release 13 I am fixing it to return the left
* hand type JUST for bitfields, so as not to break something that is
* known to work.
*/
if (exp->ex_ExpL->ex_Type->Id == TID_BITFIELD)
exp->ex_Type = exp->ex_ExpL->ex_Type;
else
exp->ex_Type = exp->ex_ExpR->ex_Type;
}
/*
* cast the right side to the left side's type
*
* exception: if left side is a bitfield right side is cast to a long
* if right side is a bitfield it is cast to a long
*
* assign takes this into account
*/
void
InitRules(pexp, t1)
Exp **pexp;
Type *t1;
{
Exp *exp = *pexp;
Type *t2;
int errorcode = EERROR_ILLEGAL_ASSIGNMENT;
t2 = exp->ex_Type;
Assert(t1);
Assert(t2);
if ((t1->Size == 0) ||
(t2->Size == 0 && t2->Id == TID_INT))
{
errorcode = EERROR_UNEXPECTED_VOID_TYPE;
}
else if (t1->Id == TID_BITFIELD)
{
if (t1->Flags & TF_UNSIGNED)
t1 = &ULongType;
else
t1 = &LongType;
if (t2->Id != TID_INT)
yerror(exp->ex_LexIdx, EERROR_ILLEGAL_BITFIELD_OP);
InsertCast(pexp, t1);
/*
* XXX ifdef'd out code entirely ... totally broken XXX
*
* First of all, it is overriding ex_Type for the RHS which
* screws up storage access to the rhs. Secondly, it cannot
* deal with a bitfield in the rhs.
*/
#ifdef NOTDEF
if (t1->Flags & TF_UNSIGNED)
t1 = &ULongType;
else
t1 = &LongType;
if (t2->Id != TID_INT)
yerror(exp->ex_LexIdx, EERROR_ILLEGAL_BITFIELD_OP);
/*
* do not insert cast as this is the lhs. GENASS.C handles assignment
* by not attempting to thrust lhs storage into rhs's return storage.
*/
exp->ex_Type = t1;
#endif
return;
}
/* exp->ex_Type = t1; */
/*
* Convert array of x to pointer to x
*/
if (t2->Id == TID_ARY)
{
InsertCast(pexp, t2 = TypeToPtrType(t2->SubType));
}
if (t1->Id == t2->Id)
{
errorcode = 0;
/* If they are both pointers, make sure that they point to the same */
/* thing before issuing a warning. */
if (t1->Id == TID_PTR)
{
CheckPointerType(exp->ex_LexIdx, exp->ex_LexIdx, t1, t2);
}
/* Not pointers, but we should check to see that the objects are the */
/* same size (since they are the same type). This check currently */
/* lets through structures which are the same size, but since we */
/* are not expecting them here we can ignore it for now??? */
else if (t1->Size != t2->Size)
{
if (t1->Id != TID_INT && t1->Id != TID_FLT)
errorcode = EERROR_ILLEGAL_ASSIGNMENT;
}
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* */
/* Check for conversions from a pointer to an integer */
/* */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * */
else if (t1->Id == TID_PTR && t2->Id == TID_INT)
{
errorcode = EWARN_INT_PTR_CONVERSION;
/* If we are converting from a constant integer to a pointer, */
/* we can let them get away with converting a constant NULL */
if (exp->ex_Stor.st_Type == ST_IntConst)
{
/* Supress the error message when they are casting a constant NULL */
if (exp->ex_Stor.st_IntConst == 0)
errorcode = 0;
}
else
{
/* We need to tell them that converting from an integer to a */
/* pointer is a bad thing. We do want to give them a more */
/* meaningful message when they are doing something that is */
/* of a different size. */
if (t1->Size != t2->Size)
errorcode = EERROR_ILLEGAL_PTR_INT_SIZE;
}
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* */
/* Check for conversions from an integer to a pointer */
/* */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * */
else if (t1->Id == TID_INT && t2->Id == TID_PTR)
{
if (t1->Size != t2->Size)
errorcode = EERROR_ILLEGAL_PTR_INT_SIZE;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* */
/* Check for conversions between floats and integers */
/* */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * */
else if ((t1->Id == TID_INT && t2->Id == TID_FLT) ||
(t1->Id == TID_FLT && t2->Id == TID_INT))
{
/* This type of conversion is really considered silent */
errorcode = 0;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* */
/* When we get here, we have run out of cases to check */
/* We must therefore assume that what they are doing */
/* is illegal and give them an error message */
/* */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * */
if (errorcode)
yerror(exp->ex_LexIdx, errorcode);
InsertCast(pexp, t1);
}
/*
* CompareRules(exp)
*
* If either side is a bit field it is cast into a long/ulong.
*
* Whichever side is the largest type, the other side is promoted. For
* example, if one side is a short and the other a byte then the
* byte is promoted to a short.
*
* If either side is unsigned or a pointer then both sides are promoted
* to unsigned.
*
* If one side is an integer constant and the other side is an
* integer quantity attempt to fit the integer constant into
* the size of the int.
*
* If either side is fp convert both sides to whichever is largest
*/
void
CompareRules(exp, bigok)
Exp *exp;
int bigok;
{
Type *t1 = exp->ex_ExpL->ex_Type;
Type *t2 = exp->ex_ExpR->ex_Type;
short doUnsigned = 0;
short size;
Type *type = &VoidType;
Assert(t1);
Assert(t2);
if (exp->ex_Flags & EF_ASSEQ)
Assert(0);
exp->ex_Type = &LongType;
if (t1->Id == TID_STRUCT || t1->Id == TID_UNION || t2->Id == TID_STRUCT || t2->Id == TID_UNION) {
if (!bigok)
yerror(exp->ex_LexIdx, EERROR_ILLEGAL_STRUCT_OP);
else if (t1->Size != t2->Size)
yerror(exp->ex_LexIdx, EERROR_ILLEGAL_STRUCT_OP);
return;
}
if (t1->Id == TID_FLT || t2->Id == TID_FLT) {
FloatingRules(exp); /* messes up ex_Type */
exp->ex_Type = &LongType;
return;
}
if (t1->Size != t2->Size) {
if (exp->ex_ExpL->ex_Stor.st_Type == ST_IntConst && t2->Id == TID_INT) {
if (CastIfConstantFit(&exp->ex_ExpL, t2))
return;
}
if (exp->ex_ExpR->ex_Stor.st_Type == ST_IntConst && t1->Id == TID_INT) {
if (CastIfConstantFit(&exp->ex_ExpR, t1))
return;
}
}
if (t1->Id == TID_INT && (t1->Flags & TF_UNSIGNED))
doUnsigned = 1;
if (t2->Id == TID_INT && (t2->Flags & TF_UNSIGNED))
doUnsigned = 1;
size = (t1->Size > t2->Size) ? t1->Size : t2->Size;
if (t1->Id == TID_ARY)
InsertCast(&exp->ex_ExpL, t1 = TypeToPtrType(t1->SubType));
if (t2->Id == TID_ARY)
InsertCast(&exp->ex_ExpR, t2 = TypeToPtrType(t2->SubType));
if (t1->Size == 0)
yerror(exp->ex_LexIdx, EERROR_UNEXPECTED_VOID_TYPE);
if (t2->Size == 0)
yerror(exp->ex_LexIdx, EERROR_UNEXPECTED_VOID_TYPE);
if (t1->Id == TID_PTR && t2->Id == TID_PTR) {
CheckPointerType(exp->ex_LexIdx, exp->ex_LexIdx, t1, t2);
return;
} else if (t1->Id == TID_PTR || t2->Id == TID_PTR) {
if (t1->Id == TID_INT) {
Exp *e1 = exp->ex_ExpL;
if (e1->ex_Stor.st_Type != ST_IntConst || e1->ex_Stor.st_IntConst != 0)
yerror(e1->ex_LexIdx, EWARN_PTR_INT_MISMATCH);
type = t2;
}
if (t2->Id == TID_INT) {
Exp *e2 = exp->ex_ExpR;
if (e2->ex_Stor.st_Type != ST_IntConst || e2->ex_Stor.st_IntConst != 0)
yerror(e2->ex_LexIdx, EWARN_PTR_INT_MISMATCH);
type = t1;
}
doUnsigned = 1;
} else {
switch(size) {
case 1:
type = (doUnsigned) ? &UCharType : &CharType;
break;
case 2:
type = (doUnsigned) ? &UShortType : &ShortType;
break;
case 4:
type = (doUnsigned) ? &ULongType : &LongType;
break;
default:
yerror(exp->ex_LexIdx, ESOFT_ILLEGAL_COMPARE);
break;
}
}
InsertCast(&exp->ex_ExpL, type);
InsertCast(&exp->ex_ExpR, type);
}
/*
* Compare rules but result is the combined type, not an integer.
* ( question-colon operator )
*/
void
MatchRules(exp)
Exp *exp;
{
Type *t1 = exp->ex_ExpL->ex_Type;
Type *t2 = exp->ex_ExpR->ex_Type;
if (t1->Size == 0 && t2->Size == 0 && t1->Id != TID_ARY && t2->Id != TID_ARY) {
exp->ex_Type = &VoidType;
} else {
CompareRules(exp, 1);
exp->ex_Type = exp->ex_ExpL->ex_Type;
}
}
/*
* For CompareRules(). If we are comparing an integer quantity < sizeof(int)
* to an integer constant and that constant fits in the quantity size, cast
* the constant to the quantity type instead of the type to an int
*/
Local int
CastIfConstantFit(pexp, type)
Exp **pexp;
Type *type;
{
Exp *exp = *pexp; /* integer constant */
short uns = exp->ex_Type->Flags & TF_UNSIGNED;
if (uns && !(type->Flags & TF_UNSIGNED)) /* not so simple */
return(0);
if (uns) {
switch(type->Size) {
case 1:
if (exp->ex_Stor.st_UIntConst < 0x100) {
InsertCast(pexp, &UCharType);
return(1);
}
break;
case 2:
if (exp->ex_Stor.st_UIntConst < 0x10000) {
InsertCast(pexp, &UShortType);
return(1);
}
break;
case 4:
break;
default:
Assert(0);
}
} else {
switch(type->Size) {
case 1:
if (exp->ex_Stor.st_IntConst >= -128 && exp->ex_Stor.st_IntConst < 128) {
InsertCast(pexp, &CharType);
return(1);
}
break;
case 2:
if (exp->ex_Stor.st_IntConst >= -32768 && exp->ex_Stor.st_IntConst < 32768) {
InsertCast(pexp, &ShortType);
return(1);
}
case 4:
break;
default:
Assert(0);
}
}
return(0);
}
/*
* Result Storage creation required?
*
* 0 yes
* 1 no, result storage already exists (even if no return storage)
* 2 no, there is no return storage
*
*/
short
AutoResultStorage(exp)
Exp *exp;
{
uword flags = exp->ex_Flags;
if (flags & EF_COND) {
if (flags & EF_CONDACK) /* was able to handle condition */
return(1);
}
if (flags & (EF_CRES|EF_PRES|EF_STACKACK))
return(1);
if (flags & EF_ASSEQ) { /* exp->ex_Stor == e1->ex_Stor */
/*
* ass= (+=, -=, ...). If a bit field, we allocate normal
* storage which will be bfsto'd later
*/
if (exp->ex_ExpL->ex_Token == TokBFExt) {
Assert(exp->ex_ExpL->ex_ExpL->ex_Flags & EF_LHSASSEQ);
AllocTmpStorage(&exp->ex_Stor, exp->ex_Type, NULL);
} else {
ReuseStorage(&exp->ex_ExpL->ex_Stor, &exp->ex_Stor);
}
if (exp->ex_Flags & EF_RNU)
FreeStorage(&exp->ex_Stor); /* no return storage, */
return(1); /* but still have result storage */
}
if (flags & EF_RNU) { /* no result */
exp->ex_Stor.st_Size = 0; /* make illegal */
return(2);
}
return(0);
}
/*
* These functions return true if result storage is available. Result
* storage is not available when the result will not be used, but we
* must be careful about EF_ASSEQ since ASSEQ does have result storage,
* just no return storage to the higher level.
*
* returns 0 <fillmeXXX>
* 1 <fillmeXXX>
* 2 temporary allocated
*/
int
CreateBinaryResultStorage(Exp *exp, short freeSub)
{
int r = 0;
if (freeSub) {
if (exp->ex_ExpL->ex_Stor.st_Type != ST_RegIndex)
FreeStorage(&exp->ex_ExpL->ex_Stor);
if (exp->ex_ExpR->ex_Stor.st_Type != ST_RegIndex)
FreeStorage(&exp->ex_ExpR->ex_Stor);
}
Assert(exp->ex_Type);
switch (AutoResultStorage(exp)) {
case 0:
Assert(exp->ex_ExpR);
AllocTmpStorage(&exp->ex_Stor, exp->ex_Type, (freeSub) ? &exp->ex_ExpR->ex_Stor : NULL);
r = 2;
break;
case 1:
r = 1;
break;
}
if (freeSub) {
if (exp->ex_ExpL->ex_Stor.st_Type == ST_RegIndex)
FreeStorage(&exp->ex_ExpL->ex_Stor);
if (exp->ex_ExpR->ex_Stor.st_Type == ST_RegIndex)
FreeStorage(&exp->ex_ExpR->ex_Stor);
}
return(r);
}
int
CreateUnaryResultStorage(Exp *exp, short freeSub)
{
if (freeSub)
FreeStorage(&exp->ex_ExpL->ex_Stor);
Assert(exp->ex_Type);
switch (AutoResultStorage(exp)) {
case 0:
if (exp->ex_Type == &VoidType)
AllocTmpStorage(&exp->ex_Stor, exp->ex_Type, NULL);
else
AllocTmpStorage(&exp->ex_Stor, exp->ex_Type, &exp->ex_ExpL->ex_Stor);
case 1:
return(1);
}
return(0);
}
int
CheckConversion(exp, t1, t2)
Exp *exp;
Type *t1;
Type *t2;
{
switch(t1->Id) {
case TID_INT:
case TID_BITFIELD:
case TID_FLT:
switch(t2->Id) {
case TID_INT:
case TID_BITFIELD:
case TID_FLT:
break;
case TID_PTR:
case TID_ARY:
yerror(exp->ex_LexIdx, EWARN_INT_PTR_CONVERSION);
break;
case TID_PROC:
case TID_STRUCT:
case TID_UNION:
yerror(exp->ex_LexIdx, EERROR_ILLEGAL_INT_CONVERSION);
return(0);
}
break;
case TID_PTR:
case TID_ARY:
switch(t2->Id) {
case TID_INT:
case TID_BITFIELD:
yerror(exp->ex_LexIdx, EWARN_PTR_INT_CONVERSION);
break;
case TID_FLT:
yerror(exp->ex_LexIdx, EERROR_ILLEGAL_PTR_CONVERSION);
return(0);
case TID_PTR:
case TID_ARY:
CheckPointerType(exp->ex_LexIdx, exp->ex_LexIdx, t1, t2);
/* if (ProtoOnlyOpt && t1->SubType->Size != t2->SubType->Size && t1->SubType->Size && t2->SubType->Size)
yerror(exp->ex_LexIdx, EWARN_PTR_PTR_MISMATCH); */
break;
case TID_PROC:
case TID_STRUCT:
case TID_UNION:
yerror(exp->ex_LexIdx, EERROR_ILLEGAL_PTR_CONVERSION);
return(0);
}
break;
case TID_PROC:
yerror(exp->ex_LexIdx, EERROR_ILLEGAL_CAST);
break;
case TID_STRUCT:
case TID_UNION:
if (t1->Size != t2->Size) {
yerror(exp->ex_LexIdx, EERROR_ILLEGAL_STRUCT_CVT);
return(0);
}
break;
}
return(1);
}